﻿using ArtMath.Core.Helper;
using ArtMath.CommonType;
using ArtMath.Resource;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;

namespace ArtMath.Command
{
    public class ModifyProperties : CommandBase
    {
        public class OldValueInfo
        {
            public string TopObjectName { get; }
            /// <summary>
            /// 直接拥有该属性的对象（不一定是属性编辑器的对象（顶级对象））
            /// </summary>
            public object Object { get; }
            public object OldValue { get; }
            public PropertyInfo PropertyInfo { get; }
            public OldValueInfo(string topName, object obj, PropertyInfo info, object oldVal)
            {
                TopObjectName = topName;
                Object = obj;
                PropertyInfo = info;
                OldValue = oldVal;
            }
            public void RollBack()
            {
                SetNewValue(OldValue);
            }
            public void SetNewValue(object newValue)
            {
                object obj = PropertyInfo.GetValue(Object, null);
                IStringSettable iss = obj as IStringSettable;
                if (iss != null)
                {
                    iss.SetFromString(newValue as string);
                }
                else
                {
                    PropertyInfo.SetValue(Object, newValue, null);
                }
            }
        }
        IList<OldValueInfo> infos;
        object newValue;
        public ModifyProperties(IList<OldValueInfo> infos, string propDesc, object newVal)
        {
            this.infos = infos;
            newValue = newVal;
            string[] oldNames = new string[infos.Count], oldVals = new string[infos.Count];
            TypeConverter tc = newValue.GetType().GetConverter();
            for (int i = 0; i < infos.Count; i++)
            {
                oldNames[i] = infos[i].TopObjectName;
                oldVals[i] = infos[i].OldValue == null ? $"({Resources.Translate("Empty")})" : tc == null ? infos[i].OldValue.ToString() : tc.ConvertToString(infos[i].OldValue);
            }
            string[] undoItemP1;
            if (propDesc == Resources.Translate("Name"))
            {
                undoItemP1 = new string[infos.Count];
                for (int i = 0; i < infos.Count; i++)
                {
                    undoItemP1[i] = newValue.ToString();
                }
            }
            else
            {
                undoItemP1 = oldNames;
            }
            string undoAdj = infos.Count > 1 ? Resources.Translate("Respectively") : string.Empty,
                redoAdj = infos.Count > 1 ? Resources.Translate("Uniformly") : string.Empty,
                newValName = tc == null ? newValue.ToString() : tc.ConvertToString(newValue);
            UndoMenuItem = new ToolStripMenuItem(string.Format(Resources.Translate("ModifyProperties"), ZipName(undoItemP1), propDesc, undoAdj, ZipName(oldVals)))
            {
                ToolTipText = string.Format(Resources.Translate("ModifyProperties"), ZipName(undoItemP1, undoItemP1.Length), propDesc, undoAdj, ZipName(oldVals, oldVals.Length)),
            };
            RedoMenuItem = new ToolStripMenuItem(string.Format(Resources.Translate("ModifyProperties"), ZipName(oldNames), propDesc, redoAdj, $"\"{newValName}\""))
            {
                ToolTipText = string.Format(Resources.Translate("ModifyProperties"), ZipName(oldNames, oldNames.Length), propDesc, redoAdj, $"\"{newValName}\""),
            };
        }
        public override int ObjectCount
        {
            get { return infos.Count; }
        }

        public override void Redo()
        {
            foreach (OldValueInfo item in infos)
            {
                item.SetNewValue(newValue);
            }
        }

        public override void Undo()
        {
            foreach (OldValueInfo item in infos)
            {
                item.RollBack();
            }
        }
    }
}
